package chatserver.objects;


import chatserver.sql.MySqlConnection;
import chatserver.container.BanInfo;
import chatserver.tools.IpSubnetFilter;
import chatserver.roles.GlobalRole;
import chatserver.roles.ChannelRole;
import chatserver.tools.Util;
import chatserver.netio.Connection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class ServerConfig {

    private MySqlConnection mySql = MySqlConnection.getInstance();
    private String host = "0.0.0.0";
    private int port = 10002;
    private int maxConnectionsPerIp = 3;
    private int maxNickLength = 64;
    private int defaultSlotsPerChannel = 64;
    private int maxConnections = 17000;
    private int maxChannels = 1024;
    private String chatBoxInfo = "chatboxserver 1.01";
    private String defaultTopic = "Welcome to the chat!";
    private String wallColor = "ff0000";
    private String wallMessage = "Server bericht";
    private int floodDelay = 1000;
    private int floodMaxRepeat = 3;
    private int floodMaxLength = 200;
    private int floodMaxWordLength = 100;    
    private boolean forbidChannelCreation = false;
        
    private List<String> allowedHosts;
    private List<BanInfo> banned;
    private List<String> reservedNames;
    private List<String> reservedChannels;
    private List<GlobalRole> globalRoles;
    private List<ChannelRole> channelRoles;
    private GlobalRole defaultGlobalRole = null;
    private GlobalRole defaultRegGlobalRole = null;
    private ChannelRole defaultChannelRole = null;
    private ChannelRole defaultCreatorChannelRole = null;

    
    public ServerConfig() {
        loadConfigFromSql();
    }


    private void loadConfigFromSql() {
        Map<String, String> config = mySql.getServerConfig();

        host = config.get("host");
        port = Util.saveIntegerValueOf(config.get("port"), port);
        maxConnectionsPerIp = Util.saveIntegerValueOf(config.get("maxloginperip"), maxConnectionsPerIp);
        maxNickLength = Util.saveIntegerValueOf(config.get("maxnicklength"), maxNickLength);
        defaultSlotsPerChannel = Util.saveIntegerValueOf(config.get("defaultslotsperchannel"), defaultSlotsPerChannel);
        maxConnections = Util.saveIntegerValueOf(config.get("maxconnections"), maxConnections);
        maxChannels = Util.saveIntegerValueOf(config.get("maxchannelcount"), maxChannels);

        chatBoxInfo = config.get("chatboxinfo");
        defaultTopic = config.get("defaulttopic");
        wallColor = config.get("wallcolor");
        wallMessage = config.get("wallmessage");
        floodDelay = Util.saveIntegerValueOf(config.get("floodelay"), floodDelay);
        floodMaxRepeat = Util.saveIntegerValueOf(config.get("floodmaxrepeat"), floodMaxRepeat);
        floodMaxLength = Util.saveIntegerValueOf(config.get("floodmaxlength"), floodMaxLength);
        floodMaxWordLength = Util.saveIntegerValueOf(config.get("floodmaxwordlength"), floodMaxWordLength);
        forbidChannelCreation =  Util.saveIntegerValueOf(config.get("forbidchannelcreation"), 0) == 1 ? true : false;
        
        
        allowedHosts = Collections.synchronizedList(mySql.getAllowedHosts());
        banned = Collections.synchronizedList(mySql.getServerBans());
        reservedNames = Collections.synchronizedList(mySql.getReservedNames());
        reservedChannels = Collections.synchronizedList(mySql.getReservedChannels());
        globalRoles = Collections.synchronizedList(mySql.getGlobalRoleList());
        channelRoles = Collections.synchronizedList(mySql.getChannelRoleList());
        
        int defaultGlobalRoleId = Util.saveIntegerValueOf(config.get("defaultserverrole"), -1);
        if(defaultGlobalRoleId != -1)
        {
            for(GlobalRole role : globalRoles)
            {
                if(role.getSqlId() == defaultGlobalRoleId)
                {
                    defaultGlobalRole = role;
                    break;
                }
            }
        }
        
        int defaultRegGlobalRoleId = Util.saveIntegerValueOf(config.get("defaultregserverrole"), -1);
        if(defaultRegGlobalRoleId != -1)
        {
            for(GlobalRole role : globalRoles)
            {
                if(role.getSqlId() == defaultRegGlobalRoleId)
                {
                    defaultRegGlobalRole = role;
                    break;
                }
            }
        }        
        
        int defaultChannelRoleId = Util.saveIntegerValueOf(config.get("defaultchannelrole"), -1);
        if(defaultChannelRoleId != -1)
        {
            for(ChannelRole role : channelRoles)
            {
                if(role.getSqlId() == defaultChannelRoleId)
                {
                    defaultChannelRole = role;
                    break;
                }
            }
        }        

        int defaultCreatorChannelRoleId = Util.saveIntegerValueOf(config.get("defaultcreatorchannelrole"), -1);
        if(defaultCreatorChannelRoleId != -1)
        {
            for(ChannelRole role : channelRoles)
            {
                if(role.getSqlId() == defaultCreatorChannelRoleId)
                {
                    defaultCreatorChannelRole = role;
                    break;
                }
            }
        }     
    
    }

    public void rehash() {
        loadConfigFromSql();
    }

    public boolean isNameReserved(String name) {
        name = name.toLowerCase();
        Iterator<String> iter = reservedNames.iterator();
        while (iter.hasNext()) {
            String r = iter.next();
            if (name.equals(r.toLowerCase())) {
                return true;
            }
            if (name.matches(r)) {
                return true;
            }
        }
        return false;
    }

    public boolean isChannelReserved(String channel) {
        channel = channel.toLowerCase();
        Iterator<String> iter = reservedChannels.iterator();
        while (iter.hasNext()) {
            String r = iter.next();
            if (channel.equals(r.toLowerCase())) {
                return true;
            }
            if (channel.matches(r)) {
                return true;
            }
        }
        return false;
    }

    
    public boolean isGlobalRoleNameTaken(String name)
    {
        for(GlobalRole role : globalRoles)
        {
          if(name.equals(role.getName()))
          {
              return true;
          }
        }
        
        return false;
    }
    
    public boolean isChannelRoleNameTaken(String name)
    {
        for(ChannelRole role : channelRoles)
        {
          if(name.equals(role.getName()))
          {
              return true;
          }
        }        
        return false;
    }
    
    public boolean isGlobalProfileTaken(String profile)
    {
        for(GlobalRole role : globalRoles)
        {
          if(profile.toLowerCase().equals(role.getProfile()))
          {
              return true;
          }
        }        
        return false;
    }
    
    public boolean isChannelProfileTaken(String profile)
    {
        for(ChannelRole role : channelRoles)
        {
          if(profile.toLowerCase().equals(role.getProfile()))
          {
              return true;
          }
        }          
        return false;
    }    
    
    public boolean isBanned(Connection c, String name) {
        name = name.toLowerCase();

        Iterator<BanInfo> iter = banned.iterator();

        while (iter.hasNext()) {

            BanInfo bi = iter.next();

            if (bi.isExpired()) {
                iter.remove();
                mySql.delServerBan(bi);
                continue;
            }

            if (bi.name.toLowerCase().equals(name)) {
                return true;
            } else if (IpSubnetFilter.ipMatches(c.getClientIp(), bi.ip, bi.ipSize)) {
                return true;
            }
        }

        return false;
    }

    public void addBan(Connection con, String name, int ipSize, long expires, String banner) {
        name = name.toLowerCase();
        BanInfo newBan = new BanInfo(name, con.getClientIp(), ipSize, expires, banner);
        banned.add(newBan);
        mySql.addServerBan(newBan);
    }

    public boolean delBanByName(String name) {
        
        boolean ret = false;
        
        name = name.toLowerCase();
        Iterator<BanInfo> iter = banned.iterator();
        while (iter.hasNext()) {
            BanInfo info = iter.next();
            if (info.name.equals(name)) {
                iter.remove();
                ret = true;
            }
        }
        
        mySql.delServerBanByName(name);
        
        return ret;
    }

    public List<BanInfo> getBanList() {
        return banned;
    }

    public List<String> getAllowedHosts() {
        return allowedHosts;
    }

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public int getMaxConnectionsPerIp() {
        return maxConnectionsPerIp;
    }

    public void setMaxConnectionsPerIp(int maxConnectionsPerIp) {
        this.maxConnectionsPerIp = maxConnectionsPerIp;
    }

    public int getMaxNickLength() {
        return maxNickLength;
    }

    public void setMaxNickLength(int maxNickLength) {
        this.maxNickLength = maxNickLength;
    }

    public int getDefaultSlotsPerChannel() {
        return defaultSlotsPerChannel;
    }

    public void setDefaultSlotsPerChannel(int defaultSlotsPerChannel) {
        this.defaultSlotsPerChannel = defaultSlotsPerChannel;
    }

    public int getMaxConnections() {
        return maxConnections;
    }

    public void setMaxConnections(int maxConnections) {
        this.maxConnections = maxConnections;
    }

    public int getMaxChannels() {
        return maxChannels;
    }

    public void setMaxChannels(int maxChannels) {
        this.maxChannels = maxChannels;
    }

    public String getChatBoxInfo() {
        return chatBoxInfo;
    }

    public void setChatBoxInfo(String chatBoxInfo) {
        this.chatBoxInfo = chatBoxInfo;
    }

    public String getDefaultTopic() {
        return defaultTopic;
    }

    public void setDefaultTopic(String defaultTopic) {
        this.defaultTopic = defaultTopic;
    }

    public int getFloodDelay() {
        return floodDelay;
    }

    public void setFloodDelay(int floodDelay) {
        this.floodDelay = floodDelay;
    }

    public int getFloodMaxRepeat() {
        return floodMaxRepeat;
    }

    public void setFloodMaxRepeat(int floodMaxRepeat) {
        this.floodMaxRepeat = floodMaxRepeat;
    }

    public int getFloodMaxLength() {
        return floodMaxLength;
    }

    public void setFloodMaxLength(int floodMaxLength) {
        this.floodMaxLength = floodMaxLength;
    }
  
    public int getFloodMaxWordLength() {
        return floodMaxWordLength;
    }

    public void setFloodMaxWordLength(int floodMaxWordLength) {
        this.floodMaxWordLength = floodMaxWordLength;
    }    
    
    public String getWallColor()
    {
        return wallColor;
    }

    public void setWallColor(String color)
    {
        wallColor = color;
    }    
    
    public String getWallMessage()
    {
        return wallMessage;
    }
    
    public List<GlobalRole> getGlobalRoles() {
        return globalRoles;
    }

    public boolean addGlobalRole(GlobalRole role)
    {
        if(isGlobalRoleNameTaken(role.getName()))
        {
            return false;
        }
        
        if(isGlobalProfileTaken(role.getProfile()))
        {
            return false;
        }
        
        role.save(true);
        globalRoles.add(role);
        return true;
    }

    public boolean addChannelRole(ChannelRole role)
    {
        if(isChannelRoleNameTaken(role.getName()))
        {
            return false;
        }
        
        if(isChannelProfileTaken(role.getProfile()))
        {
            return false;
        }
        
        role.save(true);
        channelRoles.add(role);
        return true;
    }  
    
    
    public boolean delGlobalRole(GlobalRole role)
    {
        if(role.getSqlId() == defaultGlobalRole.getSqlId())
        {
            return false;
        }
        
        if(role.getSqlId() == defaultRegGlobalRole.getSqlId())
        {
            return false;
        }
          
        if(mySql.isGlobalRoleInUse(role.getSqlId()))
        {
            return false;
        }
        
        if(!globalRoles.contains(role))
        {
            return false;
        }
        
        globalRoles.remove(role);
        mySql.delGlobalRole(role.getSqlId());
        
        return true;
    }
    
    public boolean delChannelRole(ChannelRole role)
    {
        if(role.getSqlId() == defaultChannelRole.getSqlId())
        {
            return false;
        } 

        if(role.getSqlId() == defaultCreatorChannelRole.getSqlId())
        {
            return false;
        }        
        
        if(mySql.isChannelRoleInUse(role.getSqlId()))
        {
            return false;
        }
        
        if(!channelRoles.contains(role))
        {
            return false;
        }
        
        channelRoles.remove(role);
        mySql.delChannelRole(role.getSqlId());
         
        return true;
    }
      
    public List<ChannelRole> getChannelRoles() {
        return channelRoles;
    }
    
    public GlobalRole getDefaultGlobalRole()
    {
        return defaultGlobalRole;
    }
    
    public GlobalRole getDefaultRegGlobalRole()
    {
        return defaultRegGlobalRole;
    }
    
    public ChannelRole getDefaultChannelRole()
    {
        return defaultChannelRole;
    }

    public ChannelRole getDefaultCreatorChannelRole()
    {
        return defaultCreatorChannelRole;
    }
    
    public GlobalRole findGlobalRoleById(int roleId)
    {
        GlobalRole ret = null;
        
        for(GlobalRole role : globalRoles)
        {
            if(role.getSqlId() == roleId)
            {
                ret = role;
                break;
            }
        }
 
        if(ret == null)
        {
            return defaultGlobalRole;
        }
        
        return ret;
    }
    
    public GlobalRole findGlobalRoleByProfile(String profile)
    {
        profile = profile.toLowerCase();
        GlobalRole ret = null;
        
        for(GlobalRole role : globalRoles)
        {
            if(role.getProfile().equals(profile))
            {
                ret = role;
                break;
            }
        }
 
        if(ret == null)
        {
            return defaultGlobalRole;
        }
        
        return ret;
    }
    
    public ChannelRole findChannelRoleById(int roleId)
    {
        ChannelRole ret = null;
        
        for(ChannelRole role : channelRoles)
        {
            if(role.getSqlId() == roleId)
            {
                ret = role;
                break;
            }
        }
 
        if(ret == null)
        {
            return defaultChannelRole;
        }
        
        return ret;
    }    
    
    public ChannelRole findChannelRoleByProfile(String profile)
    {
        profile = profile.toLowerCase();
        ChannelRole ret = null;
        
        for(ChannelRole role : channelRoles)
        {
            if(role.getProfile().equals(profile))
            {
                ret = role;
                break;
            }
        }
 
        if(ret == null)
        {
            return defaultChannelRole;
        }
        
        return ret;
    }    
 
}
